{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "c015b59e-1187-4d45-b2af-7b4c5a9512e1",
   "metadata": {},
   "source": [
    "# Letta Python Client \n",
    "Welcome to the Letta tutorial! In this tutorial, we'll go through how to create a basic user-client for Letta and create a custom agent with long term memory. \n",
    "\n",
    "Letta runs *agents-as-a-service*, so agents can run independently on a server. For this tutorial, we will run a local version of the client which does not require a server, but still allows you to see some of Letta's capabilities. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a34fe313-f63e-4f36-9142-f681431bbb91",
   "metadata": {},
   "outputs": [],
   "source": [
    "!pip install git+https://github.com/cpacker/MemGPT.git@tutorials"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "191c1cf1-03e6-411a-8409-003caa8530f5",
   "metadata": {},
   "source": [
    "### Setup your OpenAI API key "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "23091690-bc50-4fbc-b48d-50b639453e36",
   "metadata": {},
   "outputs": [],
   "source": [
    "import os \n",
    "\n",
    "os.environ[\"OPENAI_API_KEY\"] = \"sk-...\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f20ad6c7-9066-45e0-88ac-40920c83cc39",
   "metadata": {},
   "source": [
    "## Part 1: Connecting to the Letta Client \n",
    "\n",
    "We create a local client which creates a quickstart configuration for OpenAI using the provided `OPENAI_API_KEY`. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9b0871a0-42af-4573-a8ba-efb4fe7e5e5a",
   "metadata": {},
   "outputs": [],
   "source": [
    "from letta.client.client import LocalClient\n",
    "\n",
    "client = LocalClient(quickstart_option=\"openai\") "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "40666896-0fa2-465e-b51b-57719de30542",
   "metadata": {},
   "source": [
    "## Part 2: Create an agent \n",
    "We'll first start with creating a basic Letta agent. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fb90f12b-acd7-4877-81e8-0e7b9eb4bd9b",
   "metadata": {},
   "outputs": [],
   "source": [
    "basic_agent = client.create_agent(\n",
    "    name=\"basic_agent\", \n",
    ")\n",
    "print(f\"Created agent: {basic_agent.name}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "94d14102-3ef8-40fe-b32e-c77d0b8df311",
   "metadata": {},
   "source": [
    "We can now send messages from the user to the agent by specifying the `agent_id`: "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3cbfef36-76f0-4f0b-990a-5d8409a676d7",
   "metadata": {},
   "outputs": [],
   "source": [
    "from letta.client.utils import pprint \n",
    "\n",
    "response = client.user_message(agent_id=basic_agent.id, message=\"hello\") \n",
    "pprint(response.messages)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b24d048e-f3cc-4830-aaa2-5e590d652bd9",
   "metadata": {},
   "source": [
    "### Adding Personalization\n",
    "We can now create a more customized agent, but specifying a custom `human` and `persona` field. \n",
    "* The *human* specifies the personalization information about the user interacting with the agent \n",
    "* The *persona* specifies the behavior and personality of the event\n",
    "\n",
    "What makes Letta unique is that the starting *persona* and *human* can change over time as the agent gains new information, enabling it to have evolving memory. We'll see an example of this later in the tutorial."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3ec35979-9102-4ea7-926e-ea7ccd501ceb",
   "metadata": {},
   "outputs": [],
   "source": [
    "# TODO: feel free to change the human and person to what you'd like \n",
    "persona = \\\n",
    "\"\"\"\n",
    "You are a friendly and helpful agent!\n",
    "\"\"\"\n",
    "\n",
    "human = \\\n",
    "\"\"\"\n",
    "I am an Accenture consultant with many specializations. My name is Sarah.\n",
    "\"\"\"\n",
    "\n",
    "custom_agent = client.create_agent(\n",
    "    name=\"custom_agent\", \n",
    "    human=human, \n",
    "    persona=persona\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "63a9a61b-58c9-4d09-a4f7-48233c72c340",
   "metadata": {},
   "source": [
    "### Viewing memory \n",
    "You can access the agent's memories through the client. There are two type of memory, *core* and *archival* memory: \n",
    "1. Core memory stores short-term memories in the LLM's context \n",
    "2. Archival memory stores long term memories in a vector database\n",
    "\n",
    "Core memory is divided into a \"human\" and \"persona\" section. You can see the agent's memories about the human below: "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b0d1840a-05ee-47c1-b5f5-89faafd96e7c",
   "metadata": {},
   "outputs": [],
   "source": [
    "print(client.get_agent_memory(agent_id=custom_agent.id)[\"core_memory\"][\"human\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "95c8a058-5d67-45b7-814b-38bb67c9acf3",
   "metadata": {},
   "source": [
    "### Evolving memory \n",
    "Letta agents have long term memory, and can evolve what they store in their memory over time. In the example below, we make a correction to the previously provided information. See how the agent processes this new information. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7e58e685-579e-4a0d-bba7-41976ea7f469",
   "metadata": {},
   "outputs": [],
   "source": [
    "response = client.user_message(agent_id=custom_agent.id, message=\"Actually, my name is Charles\") \n",
    "pprint(response.messages)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "af2a2dd6-925e-49b2-ab01-bf837f33b26c",
   "metadata": {},
   "source": [
    "Now lets see what the agent's memory looks like again: "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "41ef4aaa-4a48-44bb-8944-855f30725d6d",
   "metadata": {},
   "outputs": [],
   "source": [
    "print(client.get_agent_memory(agent_id=custom_agent.id)[\"core_memory\"][\"human\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "66da949b-1084-4b87-b77c-6cbd4a822b34",
   "metadata": {},
   "source": [
    "## 🎉 Congrats, you're done with day 1 of Letta! \n",
    "For day 2, we'll go over how to connect *data sources* to Letta to run RAG agents. "
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "letta",
   "language": "python",
   "name": "letta"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
